/*
 * graph2D
 * Copyright (c) 2009 Shun Moriya <shun@mnu.sakura.ne.jp>
 *
 * The MIT License
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#if !defined(___GRAPH2D_BUTTON_H___)
#include "button.h"
#endif

#if !defined(___GRAPH2D_DESKTOP_H___)
#include "desktop.h"
#endif

#if !defined(___GRAPHC2D_MENU_H___)
#include "menu.h"
#endif

#if !defined(___GRAPH2D_VARIABLE_CONTAINER_H___)
#include "variableContainer.h"
#endif

#include <cassert>

#define MENU_CAPTION_TEXT_SIZE (14)

namespace Graph2D
{
	/*!
	 */
	Menu::Menu()
		: paddingSize(3)
		, dirty(false)
	{
		setType(TYPE_MENU);
		setFrameStyle(FRAME_STYLE_NORMAL);
		setColor(0.2f, 0.2f, 1.0f, 0.8f, 0.0f);
		setLeftFrameSize(5.f);
		setTopFrameSize(5.f);
		setRightFrameSize(5.f);
		setBottomFrameSize(5.f);

		// キャプション
		caption.setFontSize(MENU_CAPTION_TEXT_SIZE);
		set(MENU_LAYER_CAPTION, caption);

		// クローズボタン
		set(MENU_LAYER_CLOSE_BUTTON, NULL);

		// コンテナ
		container.setOwnerDraw(true);
		container.setScrollable(true);
		set(MENU_LAYER_CONTAINER, container);
	}

	/*!
	 */
	Menu::~Menu()
	{
	}

	////////////////////////////////////////////////////////////////////////////////////////////////
	/*!
	 * @return	閉じるボタン(ImageButton)オブジェクト
	 */
	ImageButton* Menu::getCloseButton()
	{
		Component* component = get(MENU_LAYER_CLOSE_BUTTON);
		if(component)
		{
			assert(component->isKindOfA(TYPE_IMAGE_BUTTON));
		}
		return reinterpret_cast<ImageButton*>(component);
	}

	/*!
	 * @param[in]	button	閉じるボタン(ImageButton)オブジェクト
	 */
	void Menu::setCloseButton(ImageButton* button)
	{
		set(MENU_LAYER_CLOSE_BUTTON, button);
		dirty = true;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////
	/*!
	 * @return	コンテナ(Container)オブジェクト
	 */
	VariableContainer* Menu::getContainer()
	{
		Component* component = get(MENU_LAYER_CONTAINER);
		assert(component && component->isKindOfA(TYPE_CONTAINER));
		return reinterpret_cast<VariableContainer*>(component);
	}

	/*!
	 * @param[in]	container	コンテナ(Container)オブジェクト
	 */
	void Menu::setContainer(VariableContainer* container)
	{
		assert(container);
		set(MENU_LAYER_CONTAINER, container);
		dirty = true;
	}

	/*!
	 * @param[in]	component	コンポーネント(Component)オブジェクト
	 * @param[in]	data		ユーザーデータ
	 */
	void Menu::addContents(Component* component, const int data)
	{
		component->setActionEvent(this);
		component->setUserData(data);
		getContainer()->append(component);
		dirty = true;
	}

	/*!
	 * @param[in]	text	ボタンのテキスト
	 * @param[in]	data	ユーザーデータ
	 */
	Button* Menu::addContents(const std::string& text, const int data)
	{
		Button* button = new Button(text);
		addContents(button, data);
		//button->release();
		dirty = true;
		return button;
	}

	/*!
	 * @param[in]	data		ユーザーデータ
	 * @return		コンポーネント(Component)オブジェクト
	 */
	Component* Menu::searchContents(const unsigned int data)
	{
		for(size_t i = 0; i < getCount(); i++)
		{
			Component* component = get(i);
			if(!component)
				continue;
			if(component->getUserData() == data)
				return component;
		}
		return NULL;
	}

	/*!
	 */
	void Menu::clearContents()
	{
		getContainer()->clear();
	}

	/*!
	 * @return	パディングサイズ
	 */
	unsigned short Menu::getPadding() const
	{
		return paddingSize;
	}

	/*!
	 * @param[in]	padding	パディングサイズ
	 */
	void Menu::setPadding(const unsigned short padding)
	{
		this->paddingSize = padding;
	}

	/*!
	 */
	void Menu::adjust()
	{
		const Vector2 clientSize = getClientSize();

		// 閉じるボタンの配置調整
		ImageButton* button = getCloseButton();
		if(button)
		{
			button->setPosition(
				clientSize.x - button->getSize().x,
				0.0f
			);
		}

		// キャプションの配置調整
		Text* caption = getCaption();
		caption->adjustSize();
		caption->setPosition(
			clientSize.x * 0.5f - caption->getSize().x * 0.5f,
			0.0f
		);

		// コンテナの配置調整
		VariableContainer* container = getContainer();

		float y = 0;
		for(size_t i = 0; i < container->getCount(); i++)
		{
			Component* child = container->get(i);
			if(child == NULL)
				continue;

			child->setPosition(0, y);
			child->setSize(clientSize.x, child->getSize().y);

			y += child->getSize().y + static_cast<float>(paddingSize);
		}

		const float captionBottom = caption->getSize().y + 2;
		const float buttonBottom = button ? (button->getSize().y + 2) : 0;
		const float containerTop = captionBottom > buttonBottom ? captionBottom : buttonBottom;

		container->setPosition(0.0f, containerTop);
		container->setSize(clientSize.x, clientSize.y - containerTop);
		container->setScrollSize(clientSize.x, y);

		dirty = false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////
	/*!
	 * @param[in]	stream	mana_streamオブジェクト
	 */
	void Menu::onSerialize(mana_stream* stream) const
	{
		super::onSerialize(stream);

		mana_stream_mark(stream);
	}

	/*!
	 * @param[in]	stream	mana_streamオブジェクト
	 */
	void Menu::onDeserialize(mana_stream* stream)
	{
		super::onDeserialize(stream);

		mana_stream_check(stream);
	}

	/*!
	 * @param[in]	drawRect	DrawRectオブジェクト
	 */
	bool Menu::onDraw(const DrawRect& drawRect)
	{
		// 変更があった場合はサイズ調整
		if(dirty)
		{
			adjust();
		}
		// 親クラスの動作を継承
		return super::onDraw(drawRect);
	}

	/*!
	 * @param[in]	component		アクションが起きたコンポーネント(Component)オブジェクト
	 * @param[in]	identification	アクションが起きたコンポーネントの番号
	 */
	void Menu::onAction(Component* component, const unsigned int identification)
	{
		(void)identification;

		if(getActionEvent())
		{
			VariableContainer* container = getContainer();
			if(container->find(component))
				getActionEvent()->onAction(container, component->getUserData());
		}
	}

	/*!
	 * @param[in]	component		アクションが起きたコンポーネント(Component)オブジェクト
	 */
	void Menu::onClick(Component* component)
	{
		if(component == get(MENU_LAYER_CLOSE_BUTTON))
		{
			onCloseButtonDown();
		}
	}

	/*!
	 */
	void Menu::onCloseButtonDown()
	{
	}

	////////////////////////////////////////////////////////////////////////////////////////////////
	/*!
	 * @param[in]	other	比較するメニュー(Menu)オブジェクト
	 */
	bool Menu::compare(const Menu& other) const
	{
		if(!super::compare(other))
			return false;

		return true;
	}
}
